/* Copyright (C) 2021-2025 Bytedance Ltd. and/or its affiliates
 * $Id: lsb.groups.c 397 2007-11-26 19:04:00Z mblack $
 * Copyright (C) 2007 Platform Computing Inc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 */

#include <unistd.h>
#include <netdb.h>
#include <string.h>

#include "lsb.h"

static struct groupInfoEnt *getGrpInfo (char **, int *, int);

static int sendGrpReq (char * ,int, struct infoReq *, struct groupInfoReply *);

struct groupInfoEnt *
lsb_usergrpinfo (char **groups, int *numGroups, int options) 
{
    options |= USER_GRP;
    return (getGrpInfo(groups, numGroups, options));

} 

struct groupInfoEnt *
lsb_hostgrpinfo(char **groups, int *numGroups, int options) 
{
    options |= HOST_GRP;
    return (getGrpInfo(groups, numGroups, options));
      
} 

static struct groupInfoEnt *
getGrpInfo(char **groups, int *numGroups, int options) 
{
    int                            i;
    char *                         clusterName = NULL;
    static  struct groupInfoReply  reply;
    struct  infoReq                groupInfo;

    memset((struct infoReq *)&groupInfo, '\0', sizeof(struct infoReq));

    if (numGroups != NULL && *numGroups < 0) {
        lsberrno = LSBE_BAD_ARG;
        return (NULL);
    }

    if (*numGroups < 0 || *numGroups > MAX_GROUPS) {
        lsberrno = LSBE_BAD_ARG;
        return (NULL);
    }

    
    if (numGroups == NULL || *numGroups == 0 || groups == NULL) {

        options |= GRP_ALL;
        groupInfo.options = options;
        groupInfo.resReq = "";
    } else {
        for (i = 0; i < *numGroups; i++) {
            if (ls_isclustername(groups[i]) <= 0 || (options & USER_GRP)) {
                continue;
            }
            options |= GRP_ALL;
            clusterName = groups[i];
	    }
	
	
        if (clusterName == NULL) {
            groupInfo.options  = options;
            groupInfo.numNames = *numGroups;
            groupInfo.names    = groups;
            groupInfo.resReq   = "";
        } else {
            groupInfo.options  = options;
            groupInfo.numNames = 0;
            groupInfo.names    = NULL;
            groupInfo.resReq   = "";
        }
    }
    
    
    if (sendGrpReq(clusterName,
                   options,
                   &groupInfo,
                   &reply) < 0) {
        *numGroups = reply.numGroups;
        return(NULL);
    }

    *numGroups = reply.numGroups;
    
    return(reply.groups);

} 
				       
static int 
sendGrpReq (char *clusterName, int options, struct infoReq *groupInfo, 
	    struct groupInfoReply *reply)
{
    XDR                    xdrs;
    char                   request_buf[MSGSIZE];
    char *                 reply_buf;
    struct LSFHeader       hdr;
    mbdReqType             mbdReqtype;
    int                    cc;
 
    xdr_lsffree(xdr_groupInfoReply, (char *)reply, &hdr);

    mbdReqtype = BATCH_GRP_INFO;
    xdrmem_create(&xdrs, request_buf, MSGSIZE, XDR_ENCODE);

    hdr.opCode = mbdReqtype;
    if (!xdr_encodeMsg(&xdrs, 
                       (char *)groupInfo, 
                       &hdr,
                       xdr_infoReq,
                       0,
                       NULL)){
        lsberrno = LSBE_XDR;
        xdr_destroy(&xdrs);
        return(-1);
    }
    
    if ((cc = callmbd (clusterName,
                       request_buf,
                       XDR_GETPOS(&xdrs), 
                       &reply_buf, 
                       &hdr,
                       NULL,
                       NULL,
                       NULL)) == -1) {
        xdr_destroy(&xdrs);
        return (-1);
    } 
    
    xdr_destroy(&xdrs);
    
    lsberrno =  hdr.opCode;
    if (lsberrno == LSBE_NO_ERROR || lsberrno == LSBE_BAD_GROUP ) {
        xdrmem_create(&xdrs,
              reply_buf,
              XDR_DECODE_SIZE_(cc),
              XDR_DECODE);

        if (!xdr_groupInfoReply(&xdrs, reply, &hdr)) {
            lsberrno = LSBE_XDR;
            xdr_destroy(&xdrs);
            if (cc) {
                free(reply_buf);
            }
            return(-1);
        }
        xdr_destroy(&xdrs);
        if (cc) {
            free(reply_buf);
        }
        return (0);
    }

    if (cc) {
        free(reply_buf);
    }
    return(-1);

}

void
freeGroupInfoReply (struct groupInfoReply *reply)
{
    int i;

    if (reply == NULL)
        return;

    for (i = 0; i < reply->numGroups; i++) {
        FREEUP(reply->groups[i].memberList);
    }

    FREEUP (reply->groups);

} 
